import Expression from "./interface/Expression";
import JoinExpression from "./JoinExpression";
import MetaData from "./MetaData";
import BaseExpression from "./abstract/BaseExpression";
import FieldExpression from "./impl/FieldExpression";
import ValueExpression from "./impl/ValueExpression";
import ObjectUtils from "../utils/ObjectUtils";
import CheckError from "../error/CheckError";
import ExtendExpression from "./abstract/ExtendExpression";
import UnchangedExpression from "./impl/UnchangedExpression";
import TableQueryBuilder from "../core/TableQueryBuilder";
import Factory from "../core/Factory";

/** where表达式 */
class WhereExpression extends BaseExpression {
    public TableQueryBuilder = TableQueryBuilder;
    public type: "where" | "limit" | "abs" = "where";

    protected in: string;
    protected left: Expression;
    protected right: Expression;


    public static and(metaData: MetaData, left: string | Record<string, any>, right?: string | number | Expression | ((fun:TableQueryBuilder)=>WhereExpression), inn: string = '=') {
        if (typeof left === 'object') {
            left = ObjectUtils.purify(left)
            let w;
            Object.keys(left).forEach((e: string) => {
                // @ts-ignore
                w = metaData.add(new WhereExpression(metaData, new FieldExpression(e, metaData.isWhere ? "and" : "where", metaData), left[e], inn))
            })
            return w || this;
        } else {
            if (right == undefined) {
                throw new CheckError("right 不可为空");
            }
            if(typeof right === 'function'){
                let me =  new Factory.MetaData(metaData)
                right(new Factory.TableQueryBuilder(me));
                me.complete().seal();
                metaData.parameter.push(...me.parameter)
                right = new UnchangedExpression(me.toSql());
            }
            return new WhereExpression(metaData, new FieldExpression(left, metaData.isWhere ? "and" : "where", metaData),right , inn);
        }
    }

    public static or(metaData: MetaData, left: string | Record<string, any>, right?: string | number | Expression | ((fun:TableQueryBuilder)=>WhereExpression), inn: string = '=') {
        if (typeof left === 'object') {
            left = ObjectUtils.purify(left)
            let w;
            Object.keys(left).forEach((e: string) => {
                // @ts-ignore
                w = metaData.add(new WhereExpression(metaData, new FieldExpression(e, metaData.isWhere ? "or" : "where", metaData), left[e], inn))
            })
            return w || this;
        } else {
            if (right == undefined) {
                throw new CheckError("right 不可为空");
            }
            if(typeof right === 'function'){
                let me = new MetaData(metaData)
                right(new TableQueryBuilder(me));
                me.complete().seal();
                me.parameter.push(...me.parameter)
                right = new UnchangedExpression(me.toSql());
            }
            return new WhereExpression(metaData, new FieldExpression(left, metaData.isWhere ? "or" : "where", metaData), right, inn);
        }
    }


    public constructor(par: MetaData, left: string | Expression, right: string | number | Expression, inn: string = '=') {
        super(par);
        par.isWhere = true;
        this.in = inn;
        this.left = typeof left === 'string' ? new FieldExpression(left, this.metadata) : left;
        this.right = ['string', 'number'].includes(typeof right) ? new ValueExpression(right as string, true, this.metadata) : right as Expression;
    }

    public subquery(callback: (table: WhereExpression) => any, alias?: string): WhereExpression {
        return ExtendExpression.subqueryFactory(this, this.metadata, callback, alias)
    }

    public toLocaSql(): string {
        return this.left.toLocaSql() + " " + this.in + " " + this.right.toLocaSql();
    }

    /** 删选语句 */
    public where(left: string | object, right?: any, inn: string = '=') {
        return WhereExpression.and(this.metadata, left, right, inn);
    }

    public orWhere(left: string | object, right?: any, inn: string = '=') {
        return WhereExpression.or(this.metadata, left, right, inn);
    }

    /** 左连接查询 */
    public leftJoin(table: string, alias?: string) {
        return new JoinExpression(this.metadata, new FieldExpression(table, "left join", this.metadata), alias);
    }

    /** 右连接查询 */
    public rightJoin(table: string, alias?: string) {
        return new JoinExpression(this.metadata, new FieldExpression(table, "right join", this.metadata), alias);
    }

    /** 内连接查询 */
    public join(table: string, alias?: string) {
        return new JoinExpression(this.metadata, new FieldExpression(table, "join", this.metadata), alias);
    }
}

export = WhereExpression;